package net.techfuser.sync;

import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:
 * @Author 左龙龙
 * @Date 21-6-2
 * @Version 1.0
 **/
@Data
@Slf4j
public class DMLData {
    private DMLType type;

    private Map<String, Object> data;
    private Map<String, Object> where;


    /**
     *
     * @param oplog     MOngodb oplog 日志
     * @param fields    用到的字段列
     */
    public DMLData(JSONObject oplog, Map<String, Class> fields){
        String op = oplog.getString("op");
        if ("i".equals(op)) {
            this.type = DMLType.INSERT;
            this.data = fetch(oplog.getJSONObject("o"), fields);
        } else if ("u".equals(op)) {
            this.type = DMLType.UPDATE;
            JSONObject o2 = oplog.getJSONObject("o2");
            this.where = fetch(o2, fields);

            this.data = new HashMap<>();
            JSONObject o = oplog.getJSONObject("o");
            for (String key : o.keySet()) {
                if ("$set".equals(key)) {
                    JSONObject setObj = o.getJSONObject("$set");
                    this.data.putAll(fetch(setObj, fields));
                } else if ("$unset".equals(key)) {
                    JSONObject unsetObj = o.getJSONObject("$unset");
                    for (String k : unsetObj.keySet()) {
                        if(fields.containsKey(k)){
                            this.data.put(k, null);
                        }
                    }
                } else {
                    log.warn("未知的操作: {}", oplog.toJSONString());
                }
            }
        } else if("d".equals(op)){
            this.type = DMLType.DELETE;
            this.where = fetch(oplog.getJSONObject("o"), fields);
        }else{
            log.warn("未识别的操作: {}", oplog.toJSONString());
        }


    }

    /**
     * 提取属性
     *
     * @param source
     * @param fields
     * @return
     */
    public Map<String, Object> fetch(JSONObject source, Map<String, Class> fields){
        if(null == source || null == fields){
            return null;
        }

        Map<String, Object> data = new HashMap<>();
        for(String key : source.keySet()){
            Class clazz = fields.get(key);
            if(String.class.equals(clazz)){
                data.put(key, source.getString(key));
            }else if(Double.class.equals(clazz)){
                data.put(key, source.getDoubleValue(key));
            }else if(Long.class.equals(clazz)){
                data.put(key, source.getLongValue(key));
            }else if(Date.class.equals(clazz)){
                data.put(key, source.getDate(key));
            }
        }

        return data;
    }


    /**
     * 是否有数据操作
     *
     * @return
     */
    public boolean vaild(){
        switch (this.type){
            case INSERT: return (null != data && data.size() > 0);
            case UPDATE: return (null != data && data.size() > 0);
            case DELETE: return (null != where && where.size() > 0);
        }

        return false;
    }
}

enum DMLType{
    INSERT, UPDATE, DELETE
}
